package com.appkubes.mall.restful.application.wx.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.appkubes.common.Response;
import com.appkubes.common.models.WxConfig;
import com.appkubes.common.utils.data.date.DateUtils;
import com.appkubes.common.utils.wechat.WechatUtils;
import com.appkubes.mall.core.entity.MallBaowen;
import com.appkubes.mall.core.entity.MallPayRecord;
import com.appkubes.mall.core.entity.MallSystem;
import com.appkubes.mall.restful.application.common.base.BaseController;
import com.appkubes.mall.restful.application.order.order.service.impl.OrderServiceImpl;
import com.appkubes.mall.restful.application.pay.strategy.wxpay.model.WXPayUtil;
import com.appkubes.mall.restful.application.pay.strategy.wxpay.model.WeiXinPayUtil;
import com.appkubes.mall.restful.application.system.basic.service.SystemService;
import com.appkubes.mall.restful.application.user.user.entity.model.WxBaseInfo;
import com.appkubes.mall.restful.application.user.user.service.impl.UserServiceLoginImpl;
import com.appkubes.mall.restful.application.wx.entity.vo.CodeVO;
import com.appkubes.mall.restful.application.wx.entity.vo.DecryptByCodeVO;
import com.appkubes.mall.restful.application.wx.entity.vo.DecryptVO;
import com.appkubes.mall.restful.application.wx.entity.vo.OpenIdVO;
import com.appkubes.mall.restful.application.wx.model.WxModel;
import com.appkubes.mall.restful.application.wx.service.BaowenService;
import com.appkubes.mall.restful.application.wx.service.PayRecordService;
import com.appkubes.mall.restful.application.wx.service.WxService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Date;
import java.util.Map;

@Api("微信模块")
@RestController
@RequestMapping("wx")
@Slf4j
public class WxController extends BaseController {

    @Autowired
    SystemService systemService;

    @Autowired
    UserServiceLoginImpl userServiceImpl;

    @Autowired
    BaowenService baowenService;

    @Autowired
    WxModel wxModel;

    @Autowired
    WxService wxService;

    @Autowired
    PayRecordService payRecordService;

    @Autowired
    OrderServiceImpl orderServiceImpl;

    private final static String deliveryAppid = "wx85fa3c688e1459eb";
    private final static String leaderAppid = "wxa9e9bf579882c5fc";

    @ApiOperation(value = "unionid登录")
    @PostMapping("/getOpenid")
    public Response getOpenid(
            @RequestParam(defaultValue = "") String code,
            @RequestParam(defaultValue = "") String iv, @RequestParam(defaultValue = "") String data) {
        MallSystem system = systemService.getCur();
        WxConfig wxConfig = new WxConfig();
        wxConfig.setAppId(system.getAppid());
        wxConfig.setAppSecret(system.getAppsecret());

        WechatUtils WechatUtils = new WechatUtils(wxConfig);
        String result = WechatUtils.getMiniAccessToken(code);
        JSONObject jsonObject = (JSONObject) JSONObject.parse(result);

        WxBaseInfo wxBaseInfo = new WxBaseInfo();
        wxBaseInfo.setOpenid(jsonObject.getString("openid"));
        wxBaseInfo.setSessionKey(jsonObject.getString("session_key"));
        if (jsonObject.getString("unionid") != null) {
            JSONObject decryptObject = WechatUtils.decryptToGetUnionid(wxBaseInfo.getSessionKey(), iv, data);
            wxBaseInfo.setUnionid(decryptObject.getString("unionId"));
            return Response.success(wxBaseInfo);
        } else {
            wxBaseInfo.setUnionid(jsonObject.getString("unionid"));
            return Response.success(wxBaseInfo);
        }
    }


    @ApiOperation(value = "配送系统unionid登录")
    @PostMapping("/getDeliveryOpenid")
    public Response getDeliveryOpenid(@RequestBody @Valid OpenIdVO openIdVO, BindingResult bindingResult) {
        MallSystem system = systemService.getCur();
        WxConfig wxConfig = new WxConfig();
        wxConfig.setAppId(system.getDeliveryAppid());
        wxConfig.setAppSecret(system.getDeliveryAppsecret());

        WechatUtils WechatUtils = new WechatUtils(wxConfig);
        String result = WechatUtils.getMiniAccessToken(openIdVO.getCode());
        JSONObject jsonObject = (JSONObject) JSONObject.parse(result);

        WxBaseInfo wxBaseInfo = new WxBaseInfo();
        wxBaseInfo.setOpenid(jsonObject.getString("openid"));
        wxBaseInfo.setSessionKey(jsonObject.getString("session_key"));
        if (jsonObject.getString("unionid") != null) {
            JSONObject decryptObject = WechatUtils.decryptToGetUnionid(wxBaseInfo.getSessionKey(), openIdVO.getIv(), openIdVO.getData());
            wxBaseInfo.setUnionid(decryptObject.getString("unionId"));
            return Response.success(wxBaseInfo);
        } else {
            wxBaseInfo.setUnionid(jsonObject.getString("unionid"));
            return Response.success(wxBaseInfo);
        }
    }

    @ApiOperation(value = "解密手机号")
    @PostMapping("/decryptByCode")
    public Response decryptByCode(@RequestBody @Valid DecryptByCodeVO decryptByCodeVO, BindingResult bindingResult) {
        // 解谜code
        MallSystem system = systemService.getCur();
        //前端有传appid时按appid获取
        if(decryptByCodeVO.getAppid()!=null){
             system = systemService.getSystemInfoByAppid(decryptByCodeVO.getAppid());
        }

        WxConfig wxConfig = new WxConfig();
        wxConfig.setAppId(system.getAppid());
        wxConfig.setAppSecret(system.getAppsecret());
        WechatUtils WechatUtils = new WechatUtils(wxConfig);
        String result = WechatUtils.getMiniAccessToken(decryptByCodeVO.getCode());
        JSONObject jsonObject = (JSONObject) JSONObject.parse(result);

        WxBaseInfo wxBaseInfo = new WxBaseInfo();
        wxBaseInfo.setOpenid(jsonObject.getString("openid"));
        wxBaseInfo.setSessionKey(jsonObject.getString("session_key"));

        JSONObject decryptObject = WechatUtils.decryptToGetUnionid(wxBaseInfo.getSessionKey(), decryptByCodeVO.getIv(), decryptByCodeVO.getData());

        return Response.success(decryptObject);
    }

    @ApiOperation(value = "解密手机号")
    @PostMapping("/decrypt")
    public Response decrypt(@RequestBody @Valid DecryptVO decryptVO, BindingResult bindingResult) {
        MallSystem system = systemService.getCur();
        String appId = system.getAppid();
        if (!decryptVO.getDelivery().toString().isEmpty()) {
            appId = deliveryAppid;
        }
        if (decryptVO.getClientType() == 2) {
            appId = leaderAppid;
        }

        WxConfig wxConfig = new WxConfig();
        wxConfig.setAppId(appId);
        wxConfig.setSessionKey(decryptVO.getKey());
        WechatUtils WechatUtils = new WechatUtils(wxConfig);
        JSONObject decryptObject = WechatUtils.decryptToGetUnionid(decryptVO.getKey(), decryptVO.getIv(), decryptVO.getData());

        return Response.success(decryptObject);
    }

    @ApiOperation("尝试通过code直接登录商城")
    @PostMapping("/getStoreUserInfoByCode")
    public Response getStoreUserInfoByCode(@RequestBody @Valid CodeVO codeVO, BindingResult bindingResult) {
        MallSystem system = systemService.getCur();
        WxConfig wxConfig = new WxConfig();
        wxConfig.setAppId(system.getAppid());
        wxConfig.setAppSecret(system.getAppsecret());

        WechatUtils WechatUtils = new WechatUtils(wxConfig);
        String result = WechatUtils.getMiniAccessToken(codeVO.getCode());
        JSONObject jsonObject = (JSONObject) JSONObject.parse(result);
        if (jsonObject.getString("errcode") != null) {
            return Response.error(jsonObject);
        }

        return Response.success();
    }

    @ApiOperation("微信回调")
    @PostMapping("/paycallback")
    public Object paycallback() {
        return this.callbackHandler(1);
    }

    @ApiOperation("微信app回调")
    @PostMapping("/paycallbackApp")
    public Object paycallbackApp() {
        return this.callbackHandler(2);
    }

    @ApiOperation("微信h5回调")
    @PostMapping("/paycallbackh5")
    public Object paycallbackh5() {
        return this.callbackHandler(3);
    }

    @ApiOperation("微信jsapi回调")
    @PostMapping("/paycallbackjsapi")
    public Object paycallbackjsapi() {
        return this.callbackHandler(4);
    }

    //回调方法
    public Object callbackHandler(int applicationType) {
        log.info("callbackHandler: applicationType: ", applicationType);
        //1 获取微信支付异步回调结果
        String xmlResult = WeiXinPayUtil.getPostStr(servletRequest);
        Map<String, String> resultMap = null;
        try {
            //将结果转成map
            resultMap = WXPayUtil.xmlToMap(xmlResult);
            //订单号
            String outTradeNo = resultMap.get("out_trade_no");
            String resultCode = resultMap.get("result_code");
            String transactionId = resultMap.get("transaction_id");
            String attach = resultMap.get("attach");
            //增加报文记录
            MallBaowen baowen = new MallBaowen();
            baowen.setXml(xmlResult);
            baowen.setOutTradeNo(outTradeNo);
            baowen.setTransactionId(transactionId);
            baowen.setAddTime(DateUtils.DateToTimestamp(new Date()));
            baowenService.save(baowen);

            //回调返回的加密签名 保存下来 下面会进行对比
            String sign = resultMap.get("sign");
            //去掉sign和利用微信回调回来的信息重新加密
            resultMap.remove("sign");

            //对比微信回调的加密与重新加密是否一致  一致即为通过 不一致说明呗改动过 加密不通过
            String resultSign = this.checkSign(resultMap, applicationType);
            if (sign.equals(resultSign)) { //验签通过
                //业务处理
                if (resultCode.equals("SUCCESS")) {
                    JSONObject jsonobj = JSON.parseObject(attach);
                    String payrecordKey = jsonobj.getString("payrecord_key");
                    MallPayRecord record = payRecordService.getById(payrecordKey);

                    if (!StringUtils.isEmpty(record.getCallbackTime())) {
                        return "SUCCESS";
                    }
                    record.setCallbackTime(DateUtils.DateToTimestamp(new Date()));
                    record.setCallbackXml(JSON.toJSONString(resultMap));
                    Boolean ret = payRecordService.updateById(record);

                    log.info("微信支付成功，通知支付成功事件:{}", record.getSourceKey());
                    orderServiceImpl.onPayCallback(record.getSourceKey());
                    if (ret) {
                        return "SUCCESS";
                    }
                } else {
                    log.info("结果支付不成功:" + baowen.getBaowenKey());
                    return "FAIL";
                }
            } else {
                log.info("签名错误11:" + baowen.getBaowenKey());
                return "FAIL";
            }
        } catch (Exception e) {
            log.info("结果异常:" + xmlResult);
            log.info(e.getMessage());
            e.printStackTrace();
            return "FAIL";
        }
        return "FAIL";
    }

    //签名验证
    private String checkSign(Map<String, String> map, int applicationType) {
        String wxKey = "";
        MallSystem system = systemService.getCur();
        if (applicationType == 2) {
            //微信app支付
            wxKey = system.getWxkey();
        } else if (applicationType == 3) {
            //微信h5支付(外部浏览器,预留)
            wxKey = wxModel.getServerKey();
        } else if (applicationType == 4) {
            //微信h5支付(公众号内,微信内置浏览器)
            wxKey = wxModel.getWxkey();
        } else {
            //小程序支付
//            wxKey = wxModel.getWxkey();
            wxKey = system.getWxkey();
        }
        try {
            //重新加密 获取加密的签名
            return WXPayUtil.generateSignature(map, wxKey); //签名
        } catch (Exception e) {
            e.printStackTrace();
            return "FAIL";
        }
    }

}
